﻿using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.JScript;

namespace BrasilFramework.Comum.Utilitario
{
    public class Eval
    {
        #region Objetos

        private static readonly object evaluator;
        private static readonly Type evaluatorTipo;

        private const string JSCRIPT_SOURCE =
          @"package Evaluator
            {
               class Evaluator
               {
                  public function Eval(expr : String) : String 
                  { 
                     return eval(expr); 
                  }
               }
            }";

        #endregion

        #region Construtor
        
        static Eval()
        {
            CompilerParameters parameters = new CompilerParameters {GenerateInMemory = true};

            CompilerResults results = new JScriptCodeProvider().CompileAssemblyFromSource(parameters, JSCRIPT_SOURCE);

            Assembly assembly = results.CompiledAssembly;
            evaluatorTipo = assembly.GetType("Evaluator.Evaluator");

            evaluator = Activator.CreateInstance(evaluatorTipo);
        }

        #endregion

        #region Métodos

        public static int EvalToInt(string statement)
        {
            var s = EvalToString(statement);
            return System.Convert.ToInt32(double.Parse(s));
        }

        public static double EvalToDouble(string statement)
        {
            var s = EvalToString(statement);
            return System.Convert.ToDouble(double.Parse(s.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)).ToString("N2"));
        }

        public static decimal EvalToDecimal(string statement)
        {
            var s = EvalToString(statement);
            return System.Convert.ToDecimal(double.Parse(s.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)).ToString("N2"));
        }

        public static string EvalToString(string statement)
        {
            var o = EvalToObject(statement);
            return o.ToString();
        }

        public static object EvalToObject(string statement)
        {
            return evaluatorTipo.InvokeMember(
                "Eval",
                BindingFlags.InvokeMethod,
                null,
                evaluator,
                new object[] {statement}
                );
        }

        #endregion
    }
}